﻿using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using CalcSharp.Core;
using CalcSharp.Core.Controlls;
using System.Drawing.Imaging;

namespace ImageConvert
{
    public partial class FormMain : Form
    {

        const string supported = "*.jpg;*.bmp;*.gif;*.jpeg;*.bmp;*.tif;*.png;*.wmf;*.emf;*.craw;*.tga;*.wdp";

        private Progress ProgressForm;
        private string OutExt;
        private MtrxStorageType t;
        private float percent;
        private List<string>[] threadfiles;
        private int ThreadCount;
        private string blendimg;

        private BlendMode bmode;
        private string reszetxt, blendmodetxt;
        private InterpolationMode imode;

        private void setThreads(int num)
        {
            this.ThreadCount = num;
            if (num > 8) this.ThreadCount = 8;
            this.threadfiles = new List<string>[this.ThreadCount];
            for (int i = 0; i < this.ThreadCount; i++) this.threadfiles[i] = new List<string>();
        }

        public FormMain()
        {
            InitializeComponent();
            this.OutExt = null;
            this.percent = 1;
            this.t = MtrxStorageType.tint24;
            this.OutExt = ".jpg";
            this.openFileDialog.Filter = "Supported images|" + supported;
            this.setThreads(Environment.ProcessorCount);
            reszetxt = "No resize";
            blendmodetxt = "Blend mode: None";
            this.TransFormText.Text = blendmodetxt + " , " + reszetxt;
            this.imode = InterpolationMode.HighQualityBilinear;
        }

        private void BtnBrowse_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.TbOutput.Text)) folderBrowserDialog.SelectedPath = "";
            else folderBrowserDialog.SelectedPath = this.TbOutput.Text;
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                this.TbOutput.Text = folderBrowserDialog.SelectedPath;
            }
        }

        public void InputEnable(bool state)
        {
            this.LbFiles.Enabled = state;
            this.TbOutput.Enabled = state;
            this.menuStrip1.Enabled = state;
            this.BtnExit.Enabled = state;
            this.BtnBrowse.Enabled = state;
            this.BtnStart.Enabled = state;
        }

        private void MenAddFiles_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK) this.LbFiles.Items.AddRange(openFileDialog.FileNames);
        }

        private void MenAddFolder_Click(object sender, EventArgs e)
        {
            string[] tmp;
            string[] exts;
            List<string> files = new List<string>();
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                exts = supported.Split(';');
                foreach (string ex in exts)
                {
                    tmp = Directory.GetFiles(folderBrowserDialog.SelectedPath, ex);
                    files.AddRange(tmp);
                }
                files.Sort();
                this.LbFiles.Items.AddRange(files.ToArray());
            }
        }

        private void MenClearList_Click(object sender, EventArgs e)
        {
            this.LbFiles.Items.Clear();
        }

        private void MenExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private string[] getFiles(string[] array, int start, int end)
        {
            List<string> files = new List<string>();
            for (int i = start; i <= end; i++) files.Add(array[i]);
            return files.ToArray();
        }

        private void BtnStart_Click(object sender, EventArgs e)
        {
            int num, lnum, i, lindex;
            string[] itms = this.UniQue();
            if (itms.Length > 0)
            {
                if (!string.IsNullOrEmpty(this.TbOutput.Text))
                {
                    if (this.ThreadCount > 1 && itms.Length >= this.ThreadCount)
                    {
                        num = itms.Length / this.ThreadCount;
                        lnum = num;
                        if (itms.Length % this.ThreadCount != 0)
                        {
                            lnum += itms.Length % this.ThreadCount;
                            if (lnum > num && this.ThreadCount > 2)
                            {
                                num += lnum / this.ThreadCount;
                                lnum = itms.Length - ((this.ThreadCount - 1) * num);
                            }
                        }
                        lindex = 0;
                        for (i = 0; i < this.ThreadCount; i++)
                        {
                            this.threadfiles[i].Clear();
                            if (i < this.ThreadCount - 1)
                            {
                                this.threadfiles[i].AddRange(this.getFiles(itms, lindex, (lindex + num) - 1));
                                lindex += num;
                            }
                            else
                            {
                                this.threadfiles[i].AddRange(this.getFiles(itms, lindex, (lindex + lnum) - 1));
                            }
                        }
                    }
                    else this.threadfiles[0].AddRange(this.getFiles(itms, 0, itms.Length - 1));
                    this.InputEnable(false);
                    this.ProgressForm = new Progress();
                    ConvertOptions.Files = this.threadfiles;
                    ConvertOptions.Outdir = this.TbOutput.Text;
                    if (!Directory.Exists(ConvertOptions.Outdir)) Directory.CreateDirectory(ConvertOptions.Outdir);
                    ConvertOptions.JpegQuality = Convert.ToInt32(this.JPEGQuality.Text.Replace("%", ""));
                    ConvertOptions.TargetExt = this.OutExt;
                    ConvertOptions.MType = this.t;
                    ConvertOptions.KeepExif = this.keepEXIFDataToolStripMenuItem.Checked;
                    ConvertOptions.InterpolMode = this.imode;
                    ConvertOptions.BlendMode = this.bmode;
                    ConvertOptions.BlendImg = this.blendimg;
                    ConvertOptions.ResizeFactor = this.percent;
                    this.Visible = false;
                    this.ProgressForm.ShowDialog();
                    this.Visible = true;
                    this.InputEnable(true);
                }
                else MessageBox.Show("Output folder not set.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else MessageBox.Show("No files to convert", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void MenDelete_Click(object sender, EventArgs e)
        {
            while (this.LbFiles.SelectedItems.Count > 0) this.LbFiles.Items.Remove(this.LbFiles.SelectedItems[0]);
        }

        private void SelectFormat(object sender, EventArgs e)
        {
            ToolStripMenuItem send = (ToolStripMenuItem)sender;
            foreach (ToolStripMenuItem it in this.FormatSelector.DropDownItems)
            {
                if (it != sender) it.Checked = false;
                else it.Checked = true;
            }
            this.JPEGQualityMenu.Enabled = false;
            this.resampleToolStripMenuItem.Enabled = false;
            this.CRawOptions.Enabled = false;
            switch (send.Name)
            {
                case "FormatBMP":
                    this.Formattext.Text = "BMP";
                    this.OutExt = ".bmp";
                    this.resampleToolStripMenuItem.Enabled = true;
                    break;
                case "FormatEmf":
                    this.Formattext.Text = "EMF";
                    this.OutExt = ".emf";
                    break;
                case "FormatGIF":
                    this.Formattext.Text = "GIF";
                    this.OutExt = ".gif";
                    break;
                case "FormatJPEG":
                    this.JPEGQualityMenu.Enabled = true;
                    this.Formattext.Text = "JPEG, " + this.JPEGQuality.Text;
                    this.OutExt = ".jpg";
                    break;
                case "FormatPNG":
                    this.Formattext.Text = "PNG";
                    this.OutExt = ".png";
                    this.resampleToolStripMenuItem.Enabled = true;
                    break;
                case "FormatTIF":
                    this.Formattext.Text = "TIF";
                    this.OutExt = ".tif";
                    this.resampleToolStripMenuItem.Enabled = true;
                    break;
                case "FormatWmf":
                    this.Formattext.Text = "WMF";
                    this.OutExt = ".wmf";
                    break;
                case "FormatCRaw":
                    this.OutExt = ".craw";
                    this.CRawOptions.Enabled = true;
                    switch (this.t)
                    {
                        case MtrxStorageType.tint24:
                            this.Formattext.Text = "CRAW, Int24";
                            break;
                        case MtrxStorageType.tfloat:
                            this.Formattext.Text = "CRAW, Float";
                            break;
                        case MtrxStorageType.tdouble:
                            this.Formattext.Text = "CRAW, Double";
                            break;
                    }
                    break;
                case "FormatHDPhoto":
                    this.JPEGQualityMenu.Enabled = true;
                    this.OutExt = ".wdp";
                    if (this.JPEGQuality.Text == "100%") this.Formattext.Text = "HD Photo, Losless";
                    else this.Formattext.Text = "HD Photo," + this.JPEGQuality.Text;
                    break;
            }
        }

        private void JPEGQuality_TextChanged(object sender, EventArgs e)
        {
            string str = JPEGQuality.Text.Replace("%", "");
            try
            {
                int qual = Convert.ToInt32(str);
                if (qual < 1) this.JPEGQuality.Text = "1%";
                else if (qual > 100) this.JPEGQuality.Text = "100%";
            }
            catch (Exception)
            {
                this.JPEGQuality.Text = "100%";
            }
            if (this.FormatHDPhoto.Checked)
            {
                if (JPEGQuality.Text == "100%") this.Formattext.Text = "HD Photo, Losless"; 
                else this.Formattext.Text = "HD Photo, " + this.JPEGQuality.Text;
            }
            else if (this.FormatJPEG.Checked) this.Formattext.Text = "JPEG, " + this.JPEGQuality.Text;
        }

        private void CrawSetup(object sender, EventArgs e)
        {
            ToolStripMenuItem send = (ToolStripMenuItem)sender;
            switch (send.Name)
            {
                case "CInt24":
                    this.CInt24.Checked = true;
                    this.CFloat.Checked = false;
                    this.CDouble.Checked = false;
                    this.Formattext.Text = "CRAW, Int24";
                    this.t = MtrxStorageType.tint24;
                    break;
                case "CFloat":
                    this.CInt24.Checked = false;
                    this.CFloat.Checked = true;
                    this.CDouble.Checked = false;
                    this.Formattext.Text = "CRAW, Float";
                    this.t = MtrxStorageType.tfloat;
                    break;
                case "CDouble":
                    this.CInt24.Checked = false;
                    this.CFloat.Checked = false;
                    this.CDouble.Checked = true;
                    this.Formattext.Text = "CRAW, Double";
                    this.t = MtrxStorageType.tdouble;
                    break;
            }
        }

        private string[] UniQue()
        {
            Dictionary<string, int> items = new Dictionary<string, int>();
            int i;
            for (i = 0; i < this.LbFiles.Items.Count; i++)
            {
                if (items.ContainsKey(this.LbFiles.Items[i].ToString())) items[this.LbFiles.Items[i].ToString()] += 1;
                else items.Add(this.LbFiles.Items[i].ToString(), 1);
            }
            return items.Keys.ToArray();
        }

        private void SetupResize(object sender, EventArgs e)
        {
            ToolStripMenuItem send = (ToolStripMenuItem)sender;
            switch (send.Name)
            {
                case "NoResize":
                    this.NoResize.Checked = true;
                    this.ResizeTo.Checked = false;
                    this.percent = 1;
                    reszetxt = "No resize";
                    this.TransFormText.Text = blendmodetxt + " , " + reszetxt;
                    break;
                case "ResizeTo":
                    this.NoResize.Checked = false;
                    this.ResizeTo.Checked = true;
                    int tmp = Convert.ToInt32(ResizeSet.Text.Replace("%", ""));
                    reszetxt = "Resize to: " + ResizeSet.Text;
                    this.TransFormText.Text = blendmodetxt + " , " + reszetxt;
                    this.percent = (float)tmp / 100;
                    break;
            }
        }

        private void ResizeSet_TextChanged(object sender, EventArgs e)
        {
            try
            {
                this.NoResize.Checked = false;
                this.ResizeTo.Checked = true;
                int tmp = Convert.ToInt32(ResizeSet.Text.Replace("%", ""));
                this.percent = (float)tmp / 100;
                if (tmp == 100) reszetxt = "No resize";
                else reszetxt = "Resize to: " + ResizeSet.Text;
                this.TransFormText.Text = blendmodetxt + " , " + reszetxt;
            }
            catch (Exception) { ; }
        }

        private void SetCpuThreads(object sender, EventArgs e)
        {
            foreach (ToolStripMenuItem it in this.CPUThreads.DropDownItems)
            {
                if (it != sender) it.Checked = false;
                else it.Checked = true;
            }
            ToolStripMenuItem send = (ToolStripMenuItem)sender;
            switch (send.Name)
            {
                case "ThrAuto":
                    this.setThreads(Environment.ProcessorCount);
                    break;
                case "Thr2":
                    this.setThreads(2);
                    break;
                case "Thr4":
                    this.setThreads(4);
                    break;
                case "Thr8":
                    this.setThreads(8);
                    break;
            }
        }

        private void OpenBlendImage_Click(object sender, EventArgs e)
        {
            openFileDialog.Multiselect = false;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                this.blendimg = openFileDialog.FileName;
                this.OpenBlendImage.Text = Path.GetFileName(blendimg);
            }
        }

        private void SetBlendMode(object sender, EventArgs e)
        {
            foreach (ToolStripMenuItem it in this.BlendModes.DropDownItems)
            {
                if (it != sender) it.Checked = false;
                else
                {
                    it.Checked = true;
                    blendmodetxt = "Blend mode: " + it.Text;
                    this.TransFormText.Text = blendmodetxt + " , " + reszetxt;
                }
                ToolStripMenuItem send = (ToolStripMenuItem)sender;
                switch (send.Name)
                {
                    case "noneToolStripMenuItem":
                        this.bmode = BlendMode.None;
                        break;
                    case "ModeAddition":
                        this.bmode = BlendMode.Addition;
                        break;
                    case "ModeBurn":
                        this.bmode = BlendMode.Burn;
                        break;
                    case "ModeDarkenOnly":
                        this.bmode = BlendMode.DarkenOnly;
                        break;
                    case "ModeDifference":
                        this.bmode = BlendMode.Difference;
                        break;
                    case "ModeDivide":
                        this.bmode = BlendMode.Divide;
                        break;
                    case "ModeDodge":
                        this.bmode = BlendMode.Dodge;
                        break;
                    case "ModeGrainExtract":
                        this.bmode = BlendMode.GrainExtract;
                        break;
                    case "ModeGrainMerge":
                        this.bmode = BlendMode.GrainMerge;
                        break;
                    case "ModeHardLight":
                        this.bmode = BlendMode.HardLight;
                        break;
                    case "ModeLightenOnly":
                        this.bmode = BlendMode.LightenOnly;
                        break;
                    case "ModeMultiply":
                        this.bmode = BlendMode.Multiply;
                        break;
                    case "ModeOverlay":
                        this.bmode = BlendMode.Overlay;
                        break;
                    case "ModeScreen":
                        this.bmode = BlendMode.Screen;
                        break;
                    case "ModeSoftLight":
                        this.bmode = BlendMode.SoftLight;
                        break;
                    case "ModeSubtract":
                        this.bmode = BlendMode.Subtract;
                        break;
                }
            }
        }

        private void SetResizemode(object sender, EventArgs e)
        {
            foreach (ToolStripMenuItem it in this.ResizeMode.DropDownItems)
            {
                if (it != sender) it.Checked = false;
                else it.Checked = true;
            }
            ToolStripMenuItem send = (ToolStripMenuItem)sender;
            switch (send.Name)
            {
                case "biLinear":
                    this.imode = InterpolationMode.HighQualityBilinear;
                    break;
                case "biCubic":
                    this.imode = InterpolationMode.HighQualityBicubic;
                    break;
                case "nearestNeighbour":
                    this.imode = InterpolationMode.NearestNeighbor;
                    break;
            }
        }

        private void SetResample(object sender, EventArgs e)
        {
            foreach (ToolStripMenuItem it in this.resampleToolStripMenuItem.DropDownItems)
            {
                if (it != sender) it.Checked = false;
                else it.Checked = true;
            }
            ToolStripMenuItem send = (ToolStripMenuItem)sender;
            switch (send.Name)
            {
                case "PFDontCare":
                    ConvertOptions.PxFormat = PixelFormat.DontCare;
                    break;
                case "PF16Bpp1555":
                    ConvertOptions.PxFormat = PixelFormat.Format16bppRgb555;
                    break;
                case "PF16bpp565":
                    ConvertOptions.PxFormat = PixelFormat.Format16bppRgb565;
                    break;
                case "PF24bpp":
                    ConvertOptions.PxFormat = PixelFormat.Format24bppRgb;
                    break;
                case "PF32bpp":
                    ConvertOptions.PxFormat = PixelFormat.Format32bppArgb;
                    break;
            }
        }
    }
}
